home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 076-100 / disk_077 / rawsamples / uudecode.d < prev    next >
Text File  |  1992-05-06  |  9KB  |  395 lines

  1. /*
  2.  * uudecode.drc
  3.  *   Decode an ASCII representation into a binary file. This is the
  4.  *   reverse of uuencode. If a parameter is given, it is the name of the
  5.  *   uuencoded file to decode. If no parameter is given, the standard
  6.  *   is read. The input file contains the name to use for the binary file
  7.  *   created. It can contain more than one file, even though uuencode
  8.  *   can't directly produce such a beast.
  9.  *
  10.  *   This is a very early program, written before the Amiga version of Draco
  11.  *   had an I/O library and include files. Hence this source file is completely
  12.  *   self contained (except for the interface routines and assembler support).
  13.  */
  14.  
  15. uint
  16.     BUFF_SIZE = 10000,        /* nice and big */
  17.     MAX_BYTES = 45,        /* maximum bytes per encoded line */
  18.     MAX_LINE = 100;        /* maximum input line we use */
  19.  
  20. ulong
  21.     MODE_READ = 1005,
  22.     MODE_WRITE = 1006;
  23.  
  24. type FileHandle_t = ulong;
  25.  
  26. extern
  27.     OpenDosLibrary(ulong version)*byte,
  28.     CloseDosLibrary()void,
  29.     GetPars(*ulong pLen; **char pPtr)void,
  30.     Output()FileHandle_t,
  31.     Input()FileHandle_t,
  32.     DeleteFile(*char name)void,
  33.     Open(*char name; ulong mode)FileHandle_t,
  34.     Close(FileHandle_t fd)void,
  35.     Read(FileHandle_t fd; *char buffer; ulong length)ulong,
  36.     Write(FileHandle_t fd; *byte buffer; ulong length)ulong,
  37.     Exit(ulong status)void;
  38.  
  39. FileHandle_t StdOut, InFd, OutFd;
  40.  
  41. [BUFF_SIZE] char InBuff;    /* buffer for input ASCII file */
  42. [BUFF_SIZE] byte OutBuff;    /* buffer for output binary file */
  43. [MAX_LINE] char LineBuff;    /* buffer for input line */
  44. [MAX_LINE] char WordBuff;    /* buffer for input word */
  45. uint InMax, InPos, OutPos, LineMax, LinePos;  /* buffer positions and counts */
  46. bool Eof;            /* true => end-of-file on input */
  47. bool GotFile;            /* true => reading from a file */
  48.  
  49. /*
  50.  * abort -
  51.  *   Local routine to cleanly abort with the given error level.
  52.  */
  53.  
  54. proc abort(uint level)void:
  55.  
  56.     if GotFile then
  57.     Close(InFd);
  58.     fi;
  59.     Exit(level);
  60. corp;
  61.  
  62. /*
  63.  * writeString -
  64.  *   Write a string to the standard output.
  65.  */
  66.  
  67. proc writeString(*char s)void:
  68.     *char p;
  69.  
  70.     p := s;
  71.     while p* ~= '\e' do
  72.     p := p + 1;
  73.     od;
  74.     if Write(StdOut, pretend(s, *byte), p - s) ~= p - s then
  75.     abort(40);
  76.     fi;
  77. corp;
  78.  
  79. /*
  80.  * writeNumber -
  81.  *   Write the ascii form of an integer to the standard output.
  82.  */
  83.  
  84. proc writeNumber(uint n)void:
  85.     [6] char buff;
  86.     *char p;
  87.  
  88.     p := &buff[5];
  89.     p* := '\e';
  90.     while
  91.     p := p - 1;
  92.     p* := n % 10 + '0';
  93.     n := n / 10;
  94.     n ~= 0
  95.     do
  96.     od;
  97.     writeString(p);
  98. corp;
  99.  
  100. /*
  101.  * flush -
  102.  *   Flush the contents of the output buffer to the output file.
  103.  */
  104.  
  105. proc flush()void:
  106.  
  107.     if OutPos ~= 0 then
  108.     if Write(OutFd, &OutBuff[0], OutPos) ~= OutPos then
  109.         writeString("Error on write - aborting.\n");
  110.         Close(OutFd);
  111.         abort(30);
  112.     fi;
  113.     OutPos := 0;
  114.     fi;
  115. corp;
  116.  
  117. /*
  118.  * addByte -
  119.  *   Add a single byte to the output file, flushing if needed.
  120.  */
  121.  
  122. proc addByte(byte b)void:
  123.  
  124.     OutBuff[OutPos] := b;
  125.     OutPos := OutPos + 1;
  126.     if OutPos = BUFF_SIZE then
  127.     flush();
  128.     fi;
  129. corp;
  130.  
  131. /*
  132.  * getChar -
  133.  *   Get the next character from the input binary file.
  134.  */
  135.  
  136. proc getChar()char:
  137.  
  138.     if InPos = InMax then
  139.     InPos := 0;
  140.     InMax := Read(InFd, &InBuff[0], BUFF_SIZE);
  141.     if InMax = 0 then
  142.         Eof := true;
  143.     fi;
  144.     fi;
  145.     InPos := InPos + 1;
  146.     InBuff[InPos - 1]
  147. corp;
  148.  
  149. /*
  150.  * getLine -
  151.  *   Read an input line into LineBuff/LineMax.
  152.  */
  153.  
  154. proc getLine()void:
  155.     char ch;
  156.  
  157.     LineMax := 0;
  158.     while
  159.     ch := getChar();
  160.     not Eof and ch ~= '\n'
  161.     do
  162.     if LineMax ~= MAX_LINE then
  163.         LineBuff[LineMax] := ch;
  164.         LineMax := LineMax + 1;
  165.     fi;
  166.     od;
  167.     LinePos := 0;
  168. corp;
  169.  
  170. /*
  171.  * getWord -
  172.  *   Peel an input word off of the input line.
  173.  */
  174.  
  175. proc getWord()*char:
  176.     *char p;
  177.  
  178.     p := &WordBuff[0];
  179.     while LinePos < LineMax and LineBuff[LinePos] ~= ' ' do
  180.     p* := LineBuff[LinePos];
  181.     p := p + 1;
  182.     LinePos := LinePos + 1;
  183.     od;
  184.     p* := '\e';
  185.     LinePos := LinePos + 1;
  186.     &WordBuff[0]
  187. corp;
  188.  
  189. /*
  190.  * isWord -
  191.  *   Compare two words for equality.
  192.  */
  193.  
  194. proc isWord(*char p, q)bool:
  195.  
  196.     while p* = q* and p* ~= '\e' do
  197.     p := p + 1;
  198.     q := q + 1;
  199.     od;
  200.     p* = q*
  201. corp;
  202.  
  203. /*
  204.  * decodeChar -
  205.  *   Decode a single character to a six bit value.
  206.  */
  207.  
  208. proc decodeChar(char ch)byte:
  209.  
  210.     if ch >= ' ' and ch <= ' ' + ((1 << 6) - 1) then
  211.     ch - ' '
  212.     elif ch = '`' then
  213.     0
  214.     else
  215.     writeString("Bad encoded character: ");
  216.     writeNumber(ch - '\e');
  217.     writeString("\n");
  218.     Close(OutFd);
  219.     abort(20);
  220.     0
  221.     fi
  222. corp;
  223.  
  224. /*
  225.  * decodeFile -
  226.  *   Decode the file given already opened descriptors, etc.
  227.  */
  228.  
  229. proc decodeFile()void:
  230.     [MAX_BYTES] byte buff;
  231.     uint count, i, j;
  232.     byte b1, b2, b3, b4;
  233.  
  234.     /* fetch and decode lines until we find one starting with "end" */
  235.     while
  236.     getLine();
  237.     not isWord(getWord(), "end")
  238.     do
  239.     /* check for a valid length line */
  240.     if LineMax < 1 or LineMax > MAX_BYTES * 4 / 3 + 1 or
  241.         (LineMax - 1) % 4 ~= 0 then
  242.         writeString("Invalid line length: ");
  243.         writeNumber(LineMax);
  244.         writeString(".\n");
  245.         Close(OutFd);
  246.         abort(20);
  247.     fi;
  248.     /* get and check the actual count of encoded bytes on this line */
  249.     count := decodeChar(LineBuff[0]);
  250.     if (LineMax - 1) / 4 ~= (count + 2) / 3 then
  251.         writeString("Invalid record length: ");
  252.         writeNumber(count);
  253.         writeString(" : ");
  254.         writeNumber(LineMax);
  255.         writeString(".\n");
  256.         Close(OutFd);
  257.         abort(20);
  258.     fi;
  259.     /* decode the line - groups of 4 characters yield three bytes */
  260.     j := 0;
  261.     i := 1;
  262.     while i ~= LineMax do
  263.         b1 := decodeChar(LineBuff[i + 0]);
  264.         b2 := decodeChar(LineBuff[i + 1]);
  265.         b3 := decodeChar(LineBuff[i + 2]);
  266.         b4 := decodeChar(LineBuff[i + 3]);
  267.         buff[j + 0] := b1 << 2 | b2 >> 4;
  268.         buff[j + 1] := b2 << 4 | b3 >> 2;
  269.         buff[j + 2] := b3 << 6 | b4;
  270.         j := j + 3;
  271.         i := i + 4;
  272.     od;
  273.     /* write out the correct number (1 - 45) of bytes */
  274.     i := 0;
  275.     while i ~= count do
  276.         addByte(buff[i]);
  277.         i := i + 1;
  278.     od;
  279.     od;
  280. corp;
  281.  
  282. /*
  283.  * decode -
  284.  *   Decode all of the encoded files in the already opened input file.
  285.  */
  286.  
  287. proc decode()void:
  288.     *char outFileName;
  289.     bool gotBegin, doneFile;
  290.  
  291.     doneFile := false;
  292.     /* decode files until there are no more left */
  293.     while not Eof do
  294.     gotBegin := false;
  295.     /* skip lines until we find a 'begin' line or we hit end-of-file */
  296.     while not Eof and not gotBegin do
  297.         getLine();
  298.         outFileName := getWord();
  299.         if isWord(outFileName, "begin") then
  300.         outFileName := getWord();
  301.         while outFileName* >= '0' and outFileName* <= '7' do
  302.             outFileName := outFileName + 1;
  303.         od;
  304.         if outFileName* = '\e' then
  305.             outFileName := getWord();
  306.             if outFileName* ~= '\e' then
  307.             gotBegin := true;
  308.             fi;
  309.         fi;
  310.         fi;
  311.     od;
  312.     /* if we just found a 'begin' line, go decode an encoded file */
  313.     if gotBegin then
  314.         writeString("Decoding file '");
  315.         writeString(outFileName);
  316.         writeString("'\n");
  317.         /* open output file, etc. */
  318.         DeleteFile(outFileName);
  319.         OutFd := Open(outFileName, MODE_WRITE);
  320.         if OutFd = 0 then
  321.         writeString("Can't open/create output file '");
  322.         writeString(outFileName);
  323.         writeString("'\n");
  324.         abort(20);
  325.         fi;
  326.         /* initialize */
  327.         OutPos := 0;
  328.         /* go decode the file */
  329.         decodeFile();
  330.         /* flush output buffer, and close file */
  331.         flush();
  332.         Close(OutFd);
  333.         doneFile := true;
  334.     fi;
  335.     od;
  336.     /* if we found no 'begin' line in the whole input file, then complain */
  337.     if not doneFile then
  338.     writeString("No 'begin' line found.\n");
  339.     abort(20);
  340.     fi;
  341. corp;
  342.  
  343. /*
  344.  * main -
  345.  *   The main program. Get the command line parameters and parse a file
  346.  *   name from them, else just use the standard input. The input file is
  347.  *   decoded into 1 or more output binary files.
  348.  */
  349.  
  350. proc main()void:
  351.     *char parPtr, inFileName;
  352.     ulong parLen;
  353.  
  354.     if OpenDosLibrary(0) ~= nil then
  355.     StdOut := Output();
  356.     GetPars(&parLen, &parPtr);
  357.     while parLen ~= 0 and
  358.         (parPtr* = ' ' or parPtr* = '\n' or parPtr* = '\r') do
  359.         parPtr := parPtr + 1;
  360.         parLen := parLen - 1;
  361.     od;
  362.     if parLen = 0 then
  363.         /* no parameter given - read from standard input */
  364.         InFd := Input();
  365.         GotFile := false;
  366.     else
  367.         inFileName := parPtr;
  368.         while parLen ~= 0 and parPtr* ~= ' ' and
  369.             parPtr* ~= '\n' and parPtr* ~= '\r' do
  370.         parPtr := parPtr + 1;
  371.         parLen := parLen - 1;
  372.         od;
  373.         parPtr* := '\e';
  374.         /* try to open the specified input file */
  375.         InFd := Open(inFileName, MODE_READ);
  376.         if InFd = 0 then
  377.         writeString("Can't open input file '");
  378.         writeString(inFileName);
  379.         writeString("'\n");
  380.         Exit(10);
  381.         fi;
  382.         GotFile := true;
  383.     fi;
  384.     /* initialize for reading the input line */
  385.     Eof := false;
  386.     InMax := 0;
  387.     InPos := 0;
  388.     decode();
  389.     if GotFile then
  390.         Close(InFd);
  391.     fi;
  392.     CloseDosLibrary();
  393.     fi;
  394. corp;
  395.